package cn.iocoder.yudao.framework.region;

import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Nonnull;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import java.util.*;

/**
 * <a href="https://blog.csdn.net/m0_68568763/article/details/135073318">汉字转拼音</a>
 *
 * @author Liu
 * @author 山野羡民（1032694760@qq.com）
 */
public final class PinyinUtils {

    /**
     * 用于将汉字转化为拼音的组合以便进行拼音
     */
    public static String generateLookup(String chinese) {
        String chineseLowerCase = chinese.toLowerCase();
        List<String> fullPinyinList = toPinyinList(chineseLowerCase);
        List<String> initialPinyinList = toPinyinFirstLetterList(fullPinyinList);
        HashSet<String> set = new HashSet<>();
        set.add(chineseLowerCase);
        for (String fullPinyin : fullPinyinList) {
            set.add(fullPinyin);
            set.add(fullPinyin.replaceAll("\\s+", ""));
            for (String initialPinyin : initialPinyinList) {
                set.addAll(generatePartLookup(initialPinyin, fullPinyin));
            }
        }
        StringBuilder sb = new StringBuilder();
        for (String s : set) {
            sb.append(s).append(" ");
        }
        for (String s : initialPinyinList) {
            sb.append(s).append(" ");
        }
        return sb.toString();
    }

    /**
     * 从完整拼音中生成各种可能的拼音组合，并将它们存储在哈希集合中
     */
    private static HashSet<String> generatePartLookup(String initialPinyin, String fullPinyin) {
        HashSet<String> set = new HashSet<>();
        String[] pys = fullPinyin.split("\\s+");
        for (int i = 1; i < pys.length; i++) {
            StringBuilder sb = new StringBuilder();
            sb.append(initialPinyin, 0, i);
            for (int j = i; j < pys.length; j++) {
                sb.append(pys[j]);
            }
            set.add(sb.toString());
        }
        return set;
    }

    /**
     * 将输入的汉字拼音集合转换为拼音首字母集合
     */
    public static List<String> toPinyinFirstLetterList(List<String> fullPinyinList) {
        HashSet<String> set = new HashSet<>();
        for (String fullPinyin : fullPinyinList) {
            String initial = fullPinyin2FirstLetter(fullPinyin);
            if (!initial.trim().isEmpty()) {
                set.add(initial);
            }
        }
        return new ArrayList<>(set);
    }


    /**
     * 将输入的汉字拼音集合转换为拼音首字母集合
     */
    public static String toPinyinFirstLetter(String chinese) {
        if ("广安市".equals(chinese)) {
            // aashi gashi 广安市 ananshi aanshi guang an shi guanganshi ganshi an an shi aas gas
            return "gas";
        }
        if ("重庆市".equals(chinese)) {
            // cqingshi chongqingshi zqshi zqingshi 重庆市 chong qing shi zhongqingshi zhong qing shi cqshi cqs zqs
            return "cqs";
        }
        return toPinyinFirstLetterList(toPinyinList(chinese)).get(0);
    }

    /**
     * 将输入的汉字转换为拼音首字母
     */
    public static String toAlphabet(String chinese) {
        if (StrUtil.isBlank(chinese)) {
            return "#";
        }
        String pinyin = toPinyinFirstLetter(chinese);
        if (StrUtil.isBlank(pinyin)) {
            return "#";
        }
        return pinyin.substring(0, 1).toUpperCase();
    }

    /**
     * 将输入的汉字拼音转换为拼音首字母集合
     */
    private static String fullPinyin2FirstLetter(String fullPinyin) {
        if (Objects.nonNull(fullPinyin) && !fullPinyin.trim().isEmpty()) {
            StringBuilder sb = new StringBuilder();
            String[] pys = fullPinyin.split("\\s+");
            for (String py : pys) {
                sb.append(py.charAt(0));
            }
            return sb.toString();
        }
        return "";
    }

    /**
     * 将汉字转化为拼音集合
     */
    public static List<String> toPinyinList(String chinese) {
        List<String[]> splitList = toPinyinSplitList(chinese);
        return split2String(splitList);
    }

    /**
     * 将汉字转化为拼音集合
     */
    @Nonnull
    public static String toPinyin(String chinese) {
        if (Objects.isNull(chinese) || chinese.trim().isEmpty()) {
            return "";
        }
        if ("广安市".equals(chinese)) {
            // aashi gashi 广安市 ananshi aanshi guang an shi guanganshi ganshi an an shi aas gas
            return "guang an shi";
        }
        if ("重庆市".equals(chinese)) {
            // cqingshi chongqingshi zqshi zqingshi 重庆市 chong qing shi zhongqingshi zhong qing shi cqshi cqs zqs
            return "chong qing shi";
        }
        String first = toPinyinList(chinese).get(0);
        if (first == null) {
            first = "";
        }
        return first;
    }

    /**
     * 将输入的字符串数组集合进行组合，生成包含所有可能组合的字符串集合，并且保持相对顺序
     */
    private static List<String> split2String(List<String[]> splitList) {
        List<String> out = new ArrayList<>();
        if (Objects.isNull(splitList) || splitList.isEmpty()) {
            return out;
        }
        Collections.addAll(out, splitList.get(0));
        for (int i = 1; i < splitList.size(); i++) {
            String[] strings = splitList.get(i);
            if (strings.length > 1) {
                ArrayList<String> temp = new ArrayList<>(out);
                for (int j = 1; j < strings.length; j++) {
                    out.addAll(temp);
                }
            }
            for (int j = 0; j < out.size(); j++) {
                int index = j / out.size();
                out.set(j, out.get(j) + " " + strings[index]);
            }
        }
        return out;
    }

    /**
     * 将汉字字符串中的每个汉字转化为拼音集合，包含多音字的情况
     */
    private static ArrayList<String[]> toPinyinSplitList(String chinese) {
        ArrayList<String[]> list = new ArrayList<>();
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        format.setVCharType(HanyuPinyinVCharType.WITH_V);
        for (int i = 0; i < chinese.length(); i++) {
            char pending = chinese.charAt(i);
            if (pending > 128) {
                try {
                    String[] pys = PinyinHelper.toHanyuPinyinStringArray(pending, format);
                    if (Objects.nonNull(pys)) {
                        list.add(new HashSet<>(Arrays.asList(pys)).toArray(new String[]{}));
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return list;
    }

}
